package com.ywy.controller;

import com.ywy.entity.User;
import com.ywy.entity.UserSign;
import com.ywy.service.MessageService;
import com.ywy.service.UserService;
import com.ywy.service.UserSignService;
import com.ywy.utils.DateUtil;
import com.ywy.utils.MD5Util;
import com.ywy.utils.RedisUtil;
import com.ywy.utils.StringUtil;
import org.apache.commons.io.FileUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 用户Controller
 *
 * @author ywy
 * @date 2022/8/25 19:14
 */
@Controller
@RequestMapping("user")
public class UserController {
    @Resource
    private UserService userService;
    @Resource
    private UserSignService userSignService;
    @Resource
    private MessageService messageService;

    @Resource
    private JavaMailSender mailSender;

    @Resource
    private RedisUtil<Integer> redisUtil;

    @Value("${mail.from}")
    private String from;

    @Value("${system.avatarPath}")
    private String userAvatarPath;

    /**
     * 用户登录请求
     *
     * @param user
     * @param loginType
     * @param session
     * @return
     */
    @ResponseBody
    @RequestMapping("login")
    public Map<String, Object> login(User user, Integer loginType, HttpSession session) {
        Map<String, Object> resultMap = new HashMap<>();
        if (StringUtil.isEmpty(user.getUsername().trim())) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "请输入用户名！");
        } else if (StringUtil.isEmpty(user.getPassword().trim())) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "请输入密码！");
        } else {
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), MD5Util.md5(user.getPassword()));
            try {
                User currentUser = userService.getByUsername(user.getUsername());
                if (!currentUser.isStatus()) {
                    resultMap.put("success", false);
                    resultMap.put("errorInfo", "该用户已经被封禁，请联系管理员！");
                } else {
                    resultMap.put("loginType", loginType);
                    // 用户选择以管理员方式登录但其不是管理员
                    if (loginType == 1 && !"ADMIN".equals(currentUser.getRoleName())) {
                        resultMap.put("success", false);
                        resultMap.put("errorInfo", "该用户不是管理员！");
                    } else {
                        // 登录
                        subject.login(token);

                        // 用户未查看的消息记录数
                        currentUser.setMessageCount(messageService.getCountByUserId(currentUser.getId()));

                        // 用户是否签到
                        UserSign userSign = userSignService.getTodaySignByUserId(currentUser.getId());
                        if (userSign != null) {
                            currentUser.setSign(true);
                            currentUser.setSignTime(userSign.getSignTime());
                            currentUser.setSignSort(userSign.getSignSort());
                        }

                        // 保存用户到session中
                        session.setAttribute("currentUser", currentUser);
                        resultMap.put("success", true);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                resultMap.put("success", false);
                resultMap.put("errorInfo", "用户名或者密码错误！");
            }
        }
        return resultMap;
    }

    /**
     * 用户注册
     *
     * @param user
     * @return
     */
    @ResponseBody
    @RequestMapping("register")
    public Map<String, Object> register(@Valid User user, BindingResult bindingResult) {
        Map<String, Object> resultMap = new HashMap<>();
        if (bindingResult.hasErrors()) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", bindingResult.getFieldError().getDefaultMessage());
        } else if (userService.getByUsername(user.getUsername()) != null) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "用户名已存在，请更换！");
        } else if (userService.getByEmail(user.getEmail()) != null) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "邮箱已存在，请更换！");
        } else {
            user.setPassword(MD5Util.md5(user.getPassword()));
            user.setRegisterDate(new Date());
            user.setAvatar("");
            userService.save(user);
            resultMap.put("success", true);
        }
        return resultMap;
    }

    /**
     * 发送邮箱验证码
     *
     * @param email
     * @param session
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("sendEmail")
    public Map<String, Object> sendEmail(String email, HttpSession session) {
        Map<String, Object> resultMap = new HashMap<>();
        if (StringUtil.isEmpty(email)) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "邮箱不能为空！");
            return resultMap;
        }
        User user = userService.getByEmail(email);
        if (user == null) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "邮箱不存在！");
            return resultMap;
        }
        String mailCode = StringUtil.randomSixNum();
        System.out.println("mailCode:" + mailCode);
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from); // 发件人
        message.setTo(email);
        message.setSubject("资源共享平台-用户找回密码"); // 主题
        message.setText("验证码：" + mailCode);
        mailSender.send(message);

        // 验证码存到session中
        session.setAttribute("mailCode", mailCode);
        session.setAttribute("userId", user.getId());
        resultMap.put("success", true);
        return resultMap;
    }

    /**
     * 重置密码
     *
     * @param captcha
     * @param session
     * @return
     */
    @ResponseBody
    @RequestMapping("resetPassword")
    public Map<String, Object> resetPassword(String captcha, HttpSession session) {
        Map<String, Object> resultMap = new HashMap<>();
        // 验证邮箱验证码
        if (StringUtil.isEmpty(captcha)) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "验证码不能为空！");
            return resultMap;
        }
        String mailCode = (String) session.getAttribute("mailCode");
        Integer userId = (Integer) session.getAttribute("userId");
        if (!captcha.equals(mailCode)) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "验证码错误！");
            return resultMap;
        }
        // 重置为默认密码
        User user = userService.getById(userId);
        user.setPassword(MD5Util.md5("123456"));
        userService.save(user);
        session.setAttribute("currentUser", user);
        resultMap.put("success", true);
        return resultMap;
    }

    /**
     * 修改密码
     *
     * @param oldPassword
     * @param password
     * @param session
     * @return
     */
    @ResponseBody
    @RequestMapping("updatePassword")
    public Map<String, Object> updatePassword(String oldPassword, String password, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");

        Map<String, Object> resultMap = new HashMap<>();
        // 验证原密码
        if (!currentUser.getPassword().equals(MD5Util.md5(oldPassword))) {
            resultMap.put("success", false);
            resultMap.put("errorInfo", "原密码错误！");
            return resultMap;
        }

        User user = userService.getById(currentUser.getId());
        // 修改为新密码
        user.setPassword(MD5Util.md5(password));
        userService.save(user);
        resultMap.put("success", true);
        return resultMap;
    }

    /**
     * 上传头像
     *
     * @param file
     * @param session
     * @return
     */
    @ResponseBody
    @RequestMapping("uploadImage")
    public Map<String, Object> uploadImage(MultipartFile file, HttpSession session) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        if (!file.isEmpty()) {
            String fileName = file.getOriginalFilename(); // 获取文件名
            String suffixName = fileName.substring(fileName.lastIndexOf(".")); // 获取文件的后缀
            String newFileName = DateUtil.formatDatePure() + suffixName; // 新文件名
            FileUtils.copyInputStreamToFile(file.getInputStream(), new File(userAvatarPath + newFileName));

            User user = (User) session.getAttribute("currentUser");
            user.setAvatar(newFileName);
            userService.save(user);
            session.setAttribute("currentUser", user);

            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("src", "/avatars/" + newFileName);
            dataMap.put("title", newFileName);

            resultMap.put("code", 0);
            resultMap.put("msg", "上传成功");
            resultMap.put("data", dataMap);
        }
        return resultMap;
    }

    /**
     * 当前登录用户是否是VIP用户
     *
     * @param session
     * @return
     */
    @ResponseBody
    @PostMapping("isVip")
    public boolean isVip(HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        User user = userService.getById(currentUser.getId());
        return user.isVip();
    }

    /**
     * 判断用户积分是否足够
     *
     * @param points
     * @param session
     * @return
     */
    @ResponseBody
    @RequestMapping("isPointEnough")
    public boolean isPointEnough(Integer points, HttpSession session) {
        User currentUser = (User) session.getAttribute("currentUser");
        User user = userService.getById(currentUser.getId());
        if (user.getPoints() >= points) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 用户签到
     * @param session
     * @return
     */
    @ResponseBody
    @RequestMapping("sign")
    public Map<String, Object> sign(HttpSession session) {
        Map<String, Object> map = new HashMap<>();
        if (session.getAttribute("currentUser") == null) {
            map.put("success", false);
            map.put("errorInfo", "大佬，请先登录下，才能签到！");
            return map;
        }
        User currentUser = (User) session.getAttribute("currentUser");
        if (currentUser.isSign()) {
            map.put("success", false);
            map.put("errorInfo", "大佬，你已经签到了，不能重复签到！");
            return map;
        }
        // 今日签到总数
        int signTotal = 0;
        try {
            if (redisUtil.hasKey("signTotal")) {
                signTotal = redisUtil.get("signTotal");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        signTotal++;
        redisUtil.set("signTotal", signTotal, DateUtil.getSecondsNextEarlyMorning());
        session.getServletContext().setAttribute("signTotal", signTotal);

        // 保存签到记录
        UserSign userSign = new UserSign();
        userSign.setUserId(currentUser.getId());
        userSign.setSignSort(signTotal);
        userSign.setSignTime(new Date());
        userSignService.save(userSign);

        // 添加积分
        User user = userService.getById(currentUser.getId());
        user.setPoints(user.getPoints() + 3);
        userService.save(user);

        user.setSign(true);
        user.setSignSort(userSign.getSignSort());
        user.setSignTime(userSign.getSignTime());

        session.setAttribute("currentUser", user);
        map.put("success", true);
        return map;
    }
}
